#!/usr/bin/python3

import sqlite3
import numpy
import math
import time
import faiss


def vecstr2numpyarray(tempstr):
    a = tempstr.replace('[', '')
    tempstr = a.replace(']', '')
    listtmp = tempstr.split(',')
    lenght = len(listtmp)
    list = []
    for i in range(lenght):
        list.append(float(listtmp[i]))
    return numpy.array(list)


class faceRecoger:
    list_DBfaceid = []              # all face id in DB
    nparray_DBfacevec = None        # all face feature vector in DB
    dbListNum = 0                   # the number of list in DB

    #def loadDB():
    def __init__(self):
        '''
        load face id DB from disk file to memory
        only run once
        '''
        print("load DB...")
        con = sqlite3.connect("../EP_faceDB/faceiddatabase.db3")
        cur = con.cursor()
        try:
            cur.execute('CREATE TABLE facedb(face_id TEXT PRIMARY KEY, face_featurevector TEXT)')
            con.commit()
        except:
            print("db is created.")

        cur.execute('SELECT * FROM facedb')
        output = cur.fetchall()
        con.close()

        self.dbListNum = len(output)

        list_DBfacevec = []
        for i in range(len(output)):
            self.list_DBfaceid.append(output[i][0]) # notice: this dataset should change if db items changed!
            tmpstr = output[i][1]
            list_DBfacevec.append(vecstr2numpyarray(tmpstr))
        self.nparray_DBfacevec = numpy.array(list_DBfacevec).astype("float32")


    def reloadDb(self):
        '''
        reload face id DB from disk file to memory
        only if db has changed.
        '''
        print("reload DB...")
        con = sqlite3.connect("../EP_faceDB/faceiddatabase.db3")
        cur = con.cursor()
        cur.execute('SELECT * FROM facedb')
        output = cur.fetchall()
        con.close()

        print("now face db records list length: ", self.dbListNum)
        print("renew face db records list length: ", len(output))
        if self.dbListNum == len(output):
            print("face DB has not changed, so do not reload face DB.")
            pass
        else:
            self.dbListNum = len(output) #update db list num info
            self.list_DBfaceid = []
            list_DBfacevec = []
            
            for i in range(len(output)):
                self.list_DBfaceid.append(output[i][0]) # notice: this dataset should change if db items changed!
                tmpstr = output[i][1]
                list_DBfacevec.append(vecstr2numpyarray(tmpstr))
            self.nparray_DBfacevec = numpy.array(list_DBfacevec).astype("float32")


    def vec2faceidProcess(self, list_facesfeaturevecs, configParams):
        '''
        recognize the input list of face feature vectors
        ps: if only one face in img, and face feature is very good, insert into faceDB
        '''
        if self.nparray_DBfacevec.shape[0] == 0:
            print("warning: face DB is empty.")
            ifKnownPerson = False
            ifInsertToDb = False
            list_facesid = [] 
            return list_facesid, ifKnownPerson, ifInsertToDb

        ifKnownPerson = False
        start = time.time()
        index = faiss.IndexFlatL2(512)
        index.add(self.nparray_DBfacevec)

        list_facesid = [] # list_facesid has same structure with list_facesfeaturevecs
        ifInsertToDb = False # if only one face in img, and face feature is very good, insert into faceDB

        list_faceid = []
        facenum = len(list_facesfeaturevecs)
        for j in range(facenum):
            curFaceVec = list_facesfeaturevecs[j]
            curFaceVec = numpy.array(curFaceVec).astype("float32")
            curFaceVec = curFaceVec.reshape((1, 512))
            
            D, I = index.search(curFaceVec, 1)
            index_min = I[0][0]
            dist_min = D[0][0]
            print("============================================================dist_min:", dist_min)

            if dist_min > configParams.config_faceRecogThreshold_reject: #30: #60: #0.5: #0.6:
                curFaceID = 'Unknow Person' #'无法识别' #+ '_' + str(int(dist_min))
                ifKnownPerson = False
            elif dist_min > configParams.config_faceRecogThreshold_notsure: #20:
                curFaceID = 'Please face to Cam' # '请正对镜头，减少面部遮挡'
                ifKnownPerson = False
            else:
                curFaceID = self.list_DBfaceid[index_min] #+ '_' + str(int(dist_min))
                ifKnownPerson = True
                if facenum == 1 and dist_min < configParams.config_faceRecogThreshold_confirm: #10:
                    ifInsertToDb = True

            list_faceid.append(curFaceID)
        end = time.time()
        print("compare feature to DB time cost(s): ", end - start)

        return list_faceid, ifKnownPerson, ifInsertToDb


if __name__ == "__main__":
    #list_DBfaceid, nparray_DBfacevec = loadDB()
    #print(list_DBfaceid)
    #print(nparray_DBfacevec)
    print("..........")
